package com.navi.loaddata.loadService.impl.hisData;

import com.navi.loaddata.core.etlException.ETLException2;
import com.navi.loaddata.core.mesEntity.MesCtPospairproduct;
import com.navi.loaddata.core.mesEntity.MesProducthistory;
import com.navi.loaddata.core.mysqlEntity.EtlConfDModel;
import com.navi.loaddata.core.oracleEntity.EtlCmnGlassV;
import com.navi.loaddata.core.oracleEntity.EtlGlassHstV;
import com.navi.loaddata.core.oracleEntity.EtlProductV;
import com.navi.loaddata.core.oracleEntity.EtlStepV;
import com.navi.loaddata.core.util.LoggerUtil;
import com.navi.loaddata.core.util.ProcessUtil;
import com.navi.loaddata.loadDao.SaveBaseDataDao;
import com.navi.loaddata.loadDao.SaveGlassHstDataDao;
import com.navi.loaddata.loadService.impl.baseData.LoadMesBaseDataService;
import com.navi.loaddata.loadService.impl.baseData.ProcessBaseDataService;
import org.apache.commons.collections.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author jay
 */
@Service
//@Transactional(transactionManager = "thirdaryPlatformTransactionManager",
//        rollbackFor = {RuntimeException.class, Exception.class})
public class LoadHisDataService {
    private static final Logger logger = LoggerFactory.getLogger(LoadHisDataService.class);
    private LoggerUtil loggerUtil = new LoggerUtil(this.getClass());

    @Autowired
    private LoadMesBaseDataService loadMesBaseDataService;
    @Autowired
    private ProcessBaseDataService processBaseDataService;
    @Autowired
    private ProcessHisDataService processHisDataService;
    @Autowired
    private LoadHisInfoService loadHisInfoService;
    @Autowired
    private SaveBaseDataDao saveBaseDataDao;
    @Autowired
    private SaveGlassHstDataDao saveGlassHstDataDao;

    public String[] loadHisDataMain(EtlConfDModel etlConfD) throws Exception {
        String[] resMsg = new String[3];
        try {
            resMsg = loadHisData(etlConfD);
            logger.info("shop={} LoadHisDataMain finish", etlConfD.getShop());
        } catch (Exception e) {
            throw e;
        }
        return resMsg;
    }

    /**
     * Load His Data
     * <p>
     * load base -> session table
     * load defect data  -> session table
     * call base proc  -> auto commit
     * call defect proc -> no auto commit
     * delete defect session table
     *
     * @param etlConfD
     */
    private String[] loadHisData(EtlConfDModel etlConfD) throws Exception {
        String shop = etlConfD.getShop();
        String[] resMsg = new String[3];
        int okCnt = 0;
        int errCnt = 0;
        String errMsg = null;

        List<MesProducthistory> hisTrackOut = loadHisInfoService.loadHisOutInfo(etlConfD);
        logger.info("shop={} His glass count {}", shop, hisTrackOut.size());

        if (!hisTrackOut.isEmpty()) {
            List<String> hisTrackInKey = getGlassInCondition(hisTrackOut);
            Map<String, MesProducthistory> hisTrackIn = loadHisInfoService.loadHisInInfo(etlConfD, hisTrackInKey);

            // base
            List<EtlStepV> etlStepVList = new ArrayList<>();
            List<EtlProductV> etlProductVList = new ArrayList<>();

            etlStepVList = loadMesBaseDataService.loadAllFinalStep(etlConfD.getShop());
            etlProductVList = loadMesBaseDataService.loadAllFinalProduct(etlConfD.getShop());

            // save base and proc
            saveBaseDataDao.saveBaseData(etlConfD, etlStepVList, etlProductVList);


//            if("ARRAY".equals(etlConfD.getShop())||"CF".equals(etlConfD.getShop())) {
            //cmn glass 可以批量入，  HST  资料也是
            Map<String, MesCtPospairproduct> mapMesCt1 = processBaseDataService.getMapMesCt1();
//            Map<String, MesCtPospairproduct> mapMesCt2 =processBaseDataService.getMapMesCt2();

            //common glass 单片保存
            List<EtlCmnGlassV> etlCmnGlassVList = new ArrayList<>();
            Map<String, String> cmnGlass = new HashedMap();
            hisTrackOut.forEach(glass -> cmnGlass.put(glass.getProductname(), glass.getProductname()));

            for (String glassId : cmnGlass.keySet()) {
                try {
                    List<MesProducthistory> commonGlassVList = loadMesBaseDataService.loadCommonGlassInfo(etlConfD, glassId);
                    EtlCmnGlassV etlCmnGlassV = processBaseDataService.processCmnGlass(etlConfD, commonGlassVList, mapMesCt1);
                    etlCmnGlassVList.add(etlCmnGlassV);
                } catch (ETLException2 e) {
                    logger.error("glassId=" + glassId + " " + e.getErrorCode().getErrorMsg() + "错误原因：\n" + LoggerUtil.stackTraceToString(e));
                    if (StringUtils.isEmpty(errMsg)) {
                        errMsg = "glassId=" + glassId + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    } else {
                        errMsg += "glassId=" + glassId + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    }
                    errCnt++;
                    continue;
                }
            }
            // save and procedure
            saveBaseDataDao.deleteCmnGlass(etlConfD);
            saveBaseDataDao.saveCmnGlass(etlConfD, etlCmnGlassVList);
            logger.info("CMN_GLASS保存成功！");
//            }

            List<MesProducthistory> leftList = new ArrayList<>();
            // His
            for (MesProducthistory his : hisTrackOut) {//LINKKEY IS NULL
                if (StringUtils.isEmpty(his.getLinkkey())) {
                    logger.warn("glassId={} opeId={} linkkey为空。忽略。", his.getProductname(), his.getOldprocessoperationname());
                    errCnt++;
                    continue;
                }
                //站点限制
                if (true == (ProcessUtil.opeLimit(his.getOldprocessoperationname()))) {
                    logger.warn("glassId={} opeId={} linkkey={} 站点信息错误。忽略。", his.getProductname(), his.getOldprocessoperationname(), his.getLinkkey());
                    errCnt++;
                    continue;
                }

                leftList.add(his);
            }
            //process
            List<EtlGlassHstV> etlGlassHstVList = new ArrayList<>();
            for (MesProducthistory his : leftList) {
                try {
                    EtlGlassHstV glassHstV = processHisDataService.processHis(etlConfD, his, hisTrackIn);
                    etlGlassHstVList.add(glassHstV);
                } catch (ETLException2 e) {
                    logger.error("glassId=" + his.getProductname() + " opeId=" + his.getOldprocessoperationname() + " linkkey=" + his.getLinkkey() + " "
                            + e.getErrorCode().getErrorMsg() + "错误原因：\n" + LoggerUtil.stackTraceToString(e));
                    if (StringUtils.isEmpty(errMsg)) {
                        errMsg = "glassId=" + his.getProductname() + " opeId=" + his.getOldprocessoperationname() + " linkkey=" + his.getLinkkey() + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    } else {
                        errMsg += "glassId=" + his.getProductname() + " opeId=" + his.getOldprocessoperationname() + " linkkey=" + his.getLinkkey() + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    }
                    errCnt++;
                    continue;
                }
            }

//
            // save
            for (EtlGlassHstV glass : etlGlassHstVList) {
                String glassId = glass.getGlassId();
                if ("CELL2".equals(etlConfD.getCellType())) glassId = glass.getChipId();
                try {
                    saveGlassHstDataDao.deleteGlassHst(etlConfD);
                }catch (ETLException2 e){
                    logger.error("{} 失败原因：{}", e.getErrorCode().getErrorMsg(), LoggerUtil.stackTraceToString(e));
                    if (StringUtils.isEmpty(errMsg)) {
                        errMsg = e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    } else {
                        errMsg +=e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    }
                    continue;
                }
                try {
                    saveGlassHstDataDao.saveGlassHstData(etlConfD, glass);
                    okCnt++;
                    logger.info("glassId={} opeId={} glassEndTime={} 保存成功!", glassId, glass.getStepId(), glass.getGlassEndTime());
                } catch (ETLException2 e) {
                    logger.error("glassId={} opeId={} glassEndTime={} 保存失败!失败原因：{}", glassId, glass.getStepId(), glass.getGlassEndTime(), LoggerUtil.stackTraceToString(e));
                    if (StringUtils.isEmpty(errMsg)) {
                        errMsg = "glassId=" + glassId + " opeId=" + glass.getStepId() + " linkkey=" + glass.getMesLinkKry() + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    } else {
                        errMsg += "glassId=" + glassId + " opeId=" + glass.getStepId() + " linkkey=" + glass.getMesLinkKry() + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    }
                    errCnt++;
                    continue;
                }

            }
        } else {
            logger.info("没有此区间的数据。"); // todo print log & save etl data
        }
        resMsg[0] = String.valueOf(okCnt);
        resMsg[1] = String.valueOf(errCnt);
        resMsg[2] = errMsg;
        return resMsg;
    }

    //String like  (glassId,linkkey),(glassId,linkkey),(glassId,linkkey)....
    private List<String> getGlassInCondition(List<MesProducthistory> curHisList) {
        List<String> glassIdsList=new ArrayList<>();
        int size = curHisList.size();
        for(int i=0;i<size;i+=1000) {
            StringBuffer glassIds = new StringBuffer();
            for (int j = 0; j < 1000; j++) {
                if(i+j<size) {
                    glassIds.append("('"+curHisList.get(i + j).getProductname()+"','"+curHisList.get(i + j).getLinkkey()+"'),");
                }
            }
            glassIds.deleteCharAt(glassIds.length() - 1);
            glassIdsList.add(glassIds.toString());
        }
        return glassIdsList;
    }

}
